/**
 * 
 */
package com.swg.cocobox.filetransfer;

import java.io.IOException;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;

import com.swg.cocobox.ResponseHandler;
import com.swg.cocobox.client.ReadWriteClient;
import com.swg.cocobox.filetransfer.command.ClientCommand;
import com.swg.cocobox.filetransfer.command.ClientCommandFactory;
import com.swg.cocobox.filetransfer.command.CommandContext;
import com.swg.cocobox.filetransfer.command.ReplyCommand;
import com.swg.cocobox.filetransfer.command.ReplyCommandFactory;

/**
 * @author satriaprayoga
 *
 */
public abstract class FileClient extends ReadWriteClient{

	private ClientCommandFactory clientCommandFactory;
	private ReplyCommandFactory replyCommandFactory;
	
	public FileClient(InetAddress address, int port) throws IOException {
		super(address, port);
	}
	
	public FileClient(String host,int port)throws IOException{
		this(InetAddress.getByName(host),port);
	}
	
	protected void send(String code,String message,ResponseHandler handler)throws IOException{
		SocketChannel channel=initConnection(address,port);
		responseMap.put(channel, handler);
		ClientCommand command=clientCommandFactory.createCommand(code, message);
		ByteBuffer commandBuffer=ByteBuffer.wrap(command.getBytes());
		synchronized (pendingData) {
			List<ByteBuffer> buffers=pendingData.get(channel);
			if(buffers==null){
				buffers=new ArrayList<ByteBuffer>();
				pendingData.put(channel, buffers);
			}
			buffers.add(commandBuffer);
		}
		selector.wakeup();
	}
	
	public void retrive(String fileName,ResponseHandler handler)throws IOException{
		send(CommandContext.RETR, fileName, handler);
	}
	
	public void cwd(ResponseHandler handler)throws IOException{
		send(CommandContext.CWD, "list", handler);
	}
	
	public void port(int port,ResponseHandler handler)throws IOException{
		send(CommandContext.PORT, String.valueOf(port), handler);
	}
	
	public void lprt(String fileName,ResponseHandler handler)throws IOException{
		send(CommandContext.LPTR, fileName, handler);
	}

	@Override
	protected void handleResponse(SocketChannel socketChannel, byte[] data,int numRead) throws IOException {
		byte[] rspData = new byte[numRead];
		System.arraycopy(data, 0, rspData, 0, numRead);
		ReplyCommand command=replyCommandFactory.parseCommand(rspData);
		
		ResponseHandler handler=responseMap.get(socketChannel);
		if(handler.handleResponse(command.getBytes())){
			socketChannel.close();
			socketChannel.keyFor(selector).cancel();
		}
		handler.waitForResponse();
		handleReply(socketChannel,command);
	}
	
	protected abstract void handleReply(SocketChannel channel,ReplyCommand command) throws IOException;
	
	public void setClientCommandFactory(
			ClientCommandFactory clientCommandFactory) {
		this.clientCommandFactory = clientCommandFactory;
	}
	
	public ClientCommandFactory getClientCommandFactory() {
		return clientCommandFactory;
	}
	
	public void setReplyCommandFactory(ReplyCommandFactory replyCommandFactory) {
		this.replyCommandFactory = replyCommandFactory;
	}
	
	public ReplyCommandFactory getReplyCommandFactory() {
		return replyCommandFactory;
	}

}
